//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "gthread.h"
#include <aura.h>

UInt32 CGhostThread::AddRef()
{
    Int32 nRefs = m_nRefs.Increment();

    return (UInt32)nRefs;
}

UInt32 CGhostThread::Release()
{
    Int32 nRefs = m_nRefs.Decrement();
    if (0 == nRefs) {
        CGhostThreadFactory factory(m_threadId);
        Ghost::S_DeleteGhost(&factory, this);
        delete this;
    }
    return (UInt32)nRefs;
}

void CGhostThread::DoAtException()
{
    if (!m_bAlive) {
        return ;
    }
    AuraSystem_GetTime((Aura_SystemTime *)&m_quitTime);
    m_bAlive = FALSE;

    return ;
}

void CGhostThread::GetQuitCode(
    /* [out] */ QuitCode * pQuitCode)
{
    assert(NULL != pQuitCode);
    assert(!m_bAlive);

    *pQuitCode = m_quitCode;
    return ;
}

void CGhostThread::GetStartTime(
    /* [out] */ SystemTime * pTime)
{
    assert(NULL != pTime);
    assert(!m_bAlive);

    *pTime = m_startTime;
    return ;
}

void CGhostThread::GetQuitTime(
    /* [out] */ SystemTime * pTime)
{
    assert(NULL != pTime);
    assert(!m_bAlive);

    *pTime = m_quitTime;
    return ;
}

void CGhostThread::GetId(
    /* [out]*/ ThreadId * pThreadId)
{
    assert(NULL != pThreadId);

    *pThreadId = m_threadId;
    return ;
}

void CGhostThread::GetName(
    /* [out] */ WStringBuf ** ppName)
{
    assert(NULL != ppName);
    assert(!m_bAlive);

    *ppName = &m_name;
    return ;
}

void CGhostThread::DoAtQuit(
    /* [in] */ QuitCode quitCode,
    /* [in] */ SystemTime startTime,
    /* [in] */ SystemTime quitTime,
    /* [in] */ WString name)
{
    assert(name.GetLength(MAXIMUM_THREAD_NAME_LENGTH) >= 0);

    m_quitCode  = quitCode;
    m_startTime = startTime;
    m_quitTime  = quitTime;

    name.IsNullOrEmpty() ? m_name.Copy(L"") : m_name.Copy(name);
    m_bAlive = FALSE;
    return ;
}

// -----------------------------------------------------
STATIC DLinkNode s_hash[GHOST_HS_SLOTS];
STATIC Aura_Handle    s_hLock;

ECode CGhostThread::S_Initialize()
{
    for (Int32 i = 0; i < GHOST_HS_SLOTS; i++) {
        s_hash[i].Initialize();
    }

    return (ECode)AuraCriticalSection_Create(&s_hLock);
}

void CGhostThread::S_Destroy()
{
    if (NULL != s_hLock) {
        AuraCriticalSection_Destroy(s_hLock);
        s_hLock = NULL;
    }
}

// -----------------------------------------------------
ECode CGhostThreadFactory::CreateGhost(
        /* [out] */ Ghost ** ppGhost,
        /* [out] */ Boolean * pbExisted)
{
    CGhostThread * pGhost = NULL;
    DLinkNode * pHead = NULL;

    assert(NULL != ppGhost);
    assert(NULL != pbExisted);

    pHead = &s_hash[GHOST_HASHCODE(m_threadId)];
    Lock(s_hLock);
    ForEachDLinkNode(CGhostThread*, pGhost, pHead)
    {
        if (pGhost->IsEqual(m_threadId)) {
            pGhost->AddRef();
            Unlock(s_hLock);

            *ppGhost = pGhost;
            *pbExisted = TRUE;
            return NOERROR;
        }
    }

    pGhost = new CGhostThread(m_threadId);
    if (NULL == pGhost) {
        Unlock(s_hLock);
        return E_OUT_OF_MEMORY;
    }
    pGhost->AddRef(); // skip referernce by itself.

    s_hash[GHOST_HASHCODE(m_threadId)].InsertLast(pGhost);
    Unlock(s_hLock);

    *ppGhost = pGhost;
    *pbExisted = FALSE;

    return NOERROR;
}

ECode CGhostThreadFactory::GetGhost(
        /* [in] */ Ghost ** ppGhost)
{
    CGhostThread * pGhost = NULL;
    DLinkNode * pHead = NULL;

    assert(NULL != ppGhost);

    pHead = &s_hash[GHOST_HASHCODE(m_threadId)];
    Lock(s_hLock);
    ForEachDLinkNode(CGhostThread*, pGhost, pHead)
    {
        if (pGhost->IsEqual(m_threadId)) {
            pGhost->AddRef();
            Unlock(s_hLock);

            *ppGhost = pGhost;
            return NOERROR;
        }
    }
    Unlock(s_hLock);
    return E_DOES_NOT_EXIST;
}

ECode CGhostThreadFactory::DeleteGhost(
        /* [in] */ Ghost * pGhost)
{
    Lock(s_hLock);
    pGhost->Detach();
    Unlock(s_hLock);

    return NOERROR;
}

